import socket
from json import loads, dumps
from time import time


class Device:
    def __init__(self, name: str, obj, valueFunc, report=True):
        self.name = name
        self.__type = type(obj)
        self.obj = obj
        self.isReport = report
        self.valueFunc = valueFunc

    def getDict(self):
        return {self.name: self.value()}

    def value(self,value=None):
        return self.valueFunc(self,value)

    def __str__(self):
        return str({'name': self.name, 'isReport': self.isReport, 'type': self.__type, "value": self.value()})


class Gateway:
    def __init__(self, device: str, key: str, parsing, ver="v1.0"):
        self.parsing = parsing
        self.devices = {}
        self.t = time()
        self.addr = []
        for i in [8600, 8700, 8800]:
            self.addr.append(socket.getaddrinfo('ndp.nlecloud.com', 8600)[0][-1])
        self.gateway = "{'t': 1,'device': '" + device + "','key': '" + key + "','ver': '" + ver + "'}"
        self.tcp = None

    def addDevice(self, devices: Device):
        if not self.devices.get(devices.name):
            self.devices[devices.name] = devices
            return True
        else:
            return False

    def removeDevice(self, name: str):
        return self.devices.pop(name)

    def connectToServer(self):
        for p in self.addr:
            self.tcp = socket.socket()
            self.tcp.settimeout(5)
            try:
                self.tcp.connect(p)
                break
            except Exception:
                pass
        try:
            self.tcp.send(self.gateway.encode())

            while True:
                try:
                    pack = loads(self.tcp.recv(1024).decode())
                    if not pack["status"]:
                        return True
                    else:
                        self.tcp.close()
                        return False
                except TimeoutError:
                    pass
        except Exception:
            self.tcp.close()
            return False

    def sendToServerKeep(self):
        if (time() - self.t >= 40):
            self.t = time()
            try:
                self.tcp.send("$#AT#".encode())
                pack = self.tcp.recv(1024).decode()
            except Exception:
                return False
            return pack == "$OK##"
        else:
            return False

    def sendToServer(self):
        pack = {}
        for name in self.devices:
            divic = self.devices.get(name)
            pack.update(divic.getDict())

            if not divic.isReport:
                continue
        if not len(pack)>0:
            return True
        data = dumps({'t': 3, 'datatype': 1, 'datas': pack, 'msgid': 123})
        try:
            self.tcp.send(data.encode())
            p = loads(self.tcp.recv(1024).decode())
            if p["status"] or p["msgid"] != 123:
                return False
        except Exception:
            return False
        return True

    def recvToServer(self):
        try:
            pack = loads(self.tcp.recv(1024).decode())
        except Exception:
            return False
        state = self.parsing(self, pack)

        try:
            # 回应服务器
            response = {"t": 6, "cmdid": pack["cmdid"], "status": int(not state), "data": pack["data"]}
            self.tcp.send(dumps(response).encode())
        except Exception:
            print("错误：回应服务器失败")

    def close(self):
        try:
            self.tcp.close()
        except Exception:
            pass


